(ns qwiz.gamecore.core
  (:use [qwiz.db.Db]))

(defn != [arg1 arg2] (not (= arg1 arg2)))

(defn in? [seq elm]
  (some #(= elm %) seq))

(defn random [max & exept]
  (let [r (Math/round (rand max)) e (first exept)]
    (if (in? e r)
      (random max e)
      r)))

(import 'java.util.Date)

(def states {:nogame "no game" :queue "queue" :sharing "sharing"})

(def game-list (ref []))

(defn now [] (. (Date.) getTime))

(declare push-user-to-queue)

(defn not-full-queue? [game] (> 3 (count @(game :users))))

(defn full-queue? [game] (= 3 (count @(game :users))))

(defn add-user-to-game [game user]
  (do
  (println user)
  (dosync
    (if (not-full-queue? game)
      (alter (game :users) conj user)
      (push-user-to-queue user)))))

(defn find-waiting-games []
  (filter #(not-full-queue? %) @game-list))

(defn find-full-queue-games []
  (filter #(full-queue? %) @game-list))

(defn create-new-game [user]
  (dosync
    (alter game-list conj
      (ref {:users (ref [user]) :name (rand) :time (now) :state (ref {:name (states :queue) :time (now)})}))))




(defn change-games-key [games key new-state]
  (dosync (doall (map #(alter % assoc key (ref new-state)) games))))

(defn start-games []
  (let [games (find-full-queue-games)]
    (change-games-key games :state {:name (states :sharing) :time (now)})
    (change-games-key games :cells [])
    (change-games-key games :question (get-rand-question))))

(defn push-user-to-queue [user]
  (let [games (find-waiting-games)]
    (if (= 0 (count games))
      (create-new-game user)
      (do
        (add-user-to-game (last games) user)
        (start-games)))))



(defn get-user-game [user]
  (first (filter #(in? @(% :users) user) @game-list)))

(defn user-not-in-game? [user]
  (= nil (get-user-game user)))

(defn user-in-game? [user]
  (not (user-not-in-game? user)))


(defn unregistered-from-game [user]
  (dosync
    (let [game (get-user-game user)]
      (if (and (not (= nil game)) (= (states :queue) (@(game :state) :name)))
        (alter (game :users)
          (fn [seq, user]
            (vec (remove #(= user %) seq))) user)))))

(defn prepare-game-for-ui [g]
  (if (not (= nil g))
    {:users (vec (map #(assoc {} :username (% :username)) @(g :users))) :name (g :name) :state @(g :state)}
    {:state {:name (states :nogame)}}))



;;;;;;;;;;;;;;;;;;;; tests ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;(push-user-to-queue {:username "user1" :password "bla"})
;(push-user-to-queue {:username "user2" :password "bla2"})
;(push-user-to-queue "user3")
;(push-user-to-queue "user4")
;(push-user-to-queue "user5")

;(start-games)
;(unregistered-from-game "user5")
(println game-list)

;(println (prepare-game-for-ui (get-user-game {:username "user1" :password "bla"})))